package com.engine.jucailinkq.common.util;

import com.alibaba.fastjson.JSONObject;
import com.engine.jucailinkq.attendance.attendanceanalysis.dto.clockpoint.ClockPointDTO;
import com.engine.jucailinkq.attendance.enums.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import weaver.general.BaseBean;
import weaver.general.Util;
import weaver.hrm.company.SubCompanyComInfo;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.text.ParseException;
import java.time.ZoneOffset;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;

@Slf4j
public class Utils<T> {
    public static Gson gson = new Gson();
    public static Type list_map_type = new TypeToken<List<Map<String,String>>>(){}.getType();
    public static Type map_type = new TypeToken<Map<String,Object>>(){}.getType();
    public static BaseBean baseBean = new BaseBean();
    /**
     * 解析格式为[{a:b,c:d}]格式的json
     * @param json
     * @return
     */
    public static List<Map<String,String>> resolveList_Map(String json){
        List<Map<String,String>> list= gson.fromJson(json,list_map_type);
        return list;
    }
    /**
     * 解析格式为{a:b,c:d}格式的json
     * @param json
     * @return
     */
    public static Map<String,Object> resolveMap(String json){
        Map<String,Object> list= gson.fromJson(json,map_type);
        return list;
    }

    /**
     * 通过接口名取得某个接口下所有实现这个接口的类
     */
    public  List<T> getAllClassByInterface(Class<?> c) {
        List<T> returnClassList = null;
        if (c.isInterface()) {
            try {
                // 获取当前的包名
                String packageName = c.getPackage().getName();
                // 获取当前包下以及子包下所以的类
                List<Class<?>> allClass = getClasses(packageName);
                if (allClass != null) {
                    returnClassList = new ArrayList();
                    for (Class<?> cls : allClass) {
                        // 判断是否是同一个接口
                        if (c.isAssignableFrom(cls)) {
                            // 本身不加入进去
                            if (!c.equals(cls)) {
                                returnClassList.add((T)cls.newInstance());
                            }
                        }
                    }
                }
            }catch (Exception e){
                baseBean.writeLog(e);
            }
        }

        return returnClassList;
    }




    /**
     * 从包package中获取所有的Class
     *
     * @param packageName
     * @return
     */
    @NotNull
    public static List<Class<?>> getClasses(String packageName) {
        // 第一个class类的集合
        List<Class<?>> classes = new ArrayList<Class<?>>();
        // 是否循环迭代
        boolean recursive = true;
        // 获取包的名字 并进行替换
        String packageDirName = packageName.replace('.', '/');
        // 定义一个枚举的集合 并进行循环来处理这个目录下的things
        Enumeration<URL> dirs;
        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            // 循环迭代下去
            while (dirs.hasMoreElements()) {
                // 获取下一个元素
                URL url = dirs.nextElement();
                // 得到协议的名称
                String protocol = url.getProtocol();
                // 如果是以文件的形式保存在服务器上
                if ("file".equals(protocol)) {
                    // 获取包的物理路径
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    // 以文件的方式扫描整个包下的文件 并添加到集合中
                    findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
                } else if ("jar".equals(protocol)) {
                    // 如果是jar包文件
                    // 定义一个JarFile
                    JarFile jar;
                    try {
                        // 获取jar
                        jar = ((JarURLConnection) url.openConnection()).getJarFile();
                        // 从此jar包 得到一个枚举类
                        Enumeration<JarEntry> entries = jar.entries();
                        // 同样的进行循环迭代
                        while (entries.hasMoreElements()) {
                            // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
                            JarEntry entry = entries.nextElement();
                            String name = entry.getName();
                            // 如果是以/开头的
                            if (name.charAt(0) == '/') {
                                // 获取后面的字符串
                                name = name.substring(1);
                            }
                            // 如果前半部分和定义的包名相同
                            if (name.startsWith(packageDirName)) {
                                int idx = name.lastIndexOf('/');
                                // 如果以"/"结尾 是一个包
                                if (idx != -1) {
                                    // 获取包名 把"/"替换成"."
                                    packageName = name.substring(0, idx).replace('/', '.');
                                }
                                // 如果可以迭代下去 并且是一个包
                                if ((idx != -1) || recursive) {
                                    // 如果是一个.class文件 而且不是目录
                                    if (name.endsWith(".class") && !entry.isDirectory()) {
                                        // 去掉后面的".class" 获取真正的类名
                                        String className = name.substring(packageName.length() + 1, name.length() - 6);
                                        try {
                                            // 添加到classes
                                            classes.add(Class.forName(packageName + '.' + className));
                                        } catch (ClassNotFoundException e) {
                                            baseBean.writeLog(e);
                                        }
                                    }
                                }
                            }
                        }
                    } catch (IOException e) {
                        baseBean.writeLog(e);
                    }
                }

            }
        } catch (IOException e) {
            baseBean.writeLog(e);
        }

        return classes;
    }

    /**
     * 以文件的形式来获取包下的所有Class
     *
     * @param packageName
     * @param packagePath
     * @param recursive
     * @param classes
     */
    public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, List<Class<?>> classes) {
        // 获取此包的目录 建立一个File
        File dir = new File(packagePath);
        // 如果不存在或者 也不是目录就直接返回
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        // 如果存在 就获取包下的所有文件 包括目录
        File[] dirfiles = dir.listFiles(new FileFilter() {
            // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
            @Override
            public boolean accept(File file) {
                return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
            }
        });
        // 循环所有文件
        for (File file : dirfiles) {
            // 如果是目录 则继续扫描
            if (file.isDirectory()) {
                findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
            } else {
                // 如果是java类文件 去掉后面的.class 只留下类名
                String className = file.getName().substring(0, file.getName().length() - 6);
                try {
                    // 添加到集合中去
                    classes.add(Class.forName(packageName + '.' + className));
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                    baseBean.writeLog(e);
                }
            }
        }
    }


    /**
     * 获得time时间内最近的前后打卡时间数据
     * @param time
     * @param clockInTimeList 打卡数据
     * @return
     */
    public static Map<ClockPointEnum,Map<String,Object>> getNearestClcokInTimeCmd(String time,List<Map<String, Object>> clockInTimeList){
        Map<ClockPointEnum,Map<String,Object>> resultMap = Maps.newHashMap();
        for (int i=0;i<clockInTimeList.size();i++){
            String signDateTime = clockInTimeList.get(i).get("signdate") +" "+clockInTimeList.get(i).get("signtime");
            int j=i+1;
            if (j > clockInTimeList.size()-1){
                j = clockInTimeList.size()-1;
            }
            String afterSignDateTime = clockInTimeList.get(j).get("signdate") +" "+clockInTimeList.get(j).get("signtime");
            if (i==0 && DateUtil.getTime(time).compareTo(DateUtil.getTime(signDateTime)) <0){
                resultMap.put(ClockPointEnum.AFTER,clockInTimeList.get(i));
            }else if (i == clockInTimeList.size()-1 && DateUtil.getTime(time).compareTo(DateUtil.getTime(signDateTime)) >0){
                resultMap.put(ClockPointEnum.BEFORE,clockInTimeList.get(i));
            }else if (DateUtil.getTime(time).compareTo(DateUtil.getTime(signDateTime)) >0 && DateUtil.getTime(time).compareTo(DateUtil.getTime(afterSignDateTime)) <0){
                resultMap.put(ClockPointEnum.BEFORE,clockInTimeList.get(i));
                resultMap.put(ClockPointEnum.AFTER,clockInTimeList.get(j));
            }else if (DateUtil.getTime(time).compareTo(DateUtil.getTime(signDateTime)) == 0){
                resultMap.put(ClockPointEnum.EQUAL,clockInTimeList.get(i));
            }
        }
        return resultMap;
    }

    /**
     * 根据核算量、核算单位，计算出具体项目时长，向上核算
     * @param hsl 核算量
     * @param hsdw 核算单位
     * @param duration 时间值
     * @param unit 时间值单位
     * @param edsc 班次额定时长
     * @return
     */
    public static double getItemduration(double hsl, String hsdw,double duration, AccountingUnitEnum unit,double edsc){
        double itemDuration = 0.0;
        BigDecimal durationBig = new BigDecimal(duration);
        BigDecimal hslBig = new BigDecimal(hsl);
        if (AccountingUnitEnum.DAY.getKey().equals(hsdw)){
            double durationDay = 0;
            if (unit.equals(AccountingUnitEnum.MINUTES)){
                durationDay = Utils.divide(Utils.divide(duration,60),edsc);

            }else if (unit.equals(AccountingUnitEnum.HOUR)){
                durationDay = Utils.divide(duration,edsc);
            }else if (unit.equals(AccountingUnitEnum.DAY)){
                durationDay=duration;
            }
            durationBig = new BigDecimal(durationDay);
            if (Double.compare(durationDay/hsl,Math.floor(durationDay/hsl)) > 0){
                durationBig = new BigDecimal(Math.floor(durationDay/hsl));
                itemDuration = durationBig.multiply(hslBig).add(hslBig,new MathContext(BigDecimal.ROUND_HALF_UP)).doubleValue();
            }else {
                itemDuration = durationBig.multiply(hslBig).divide(hslBig,BigDecimal.ROUND_DOWN).doubleValue();
            }
        }else if (AccountingUnitEnum.ONCE.getKey().equals(hsdw)){
            itemDuration=hsl;
        }else if (AccountingUnitEnum.HOUR.getKey().equals(hsdw)){
            double durationHour = 0;
            if (unit.equals(AccountingUnitEnum.MINUTES)){
                durationHour = duration/60.0;
            }else if (unit.equals(AccountingUnitEnum.HOUR)){
                durationHour = duration;
            }else if (unit.equals(AccountingUnitEnum.DAY)){
                durationHour = duration*edsc;
            }
            durationBig = new BigDecimal(durationHour);
            if ((durationHour/hsl) > Math.floor(durationHour/hsl)){
                // (durationHour/hsl)*hsl+hsl
                durationBig = new BigDecimal(Math.floor(durationHour/hsl));
                itemDuration = durationBig.multiply(hslBig).add(hslBig,new MathContext(BigDecimal.ROUND_HALF_UP)).doubleValue();
            }else {
                itemDuration = durationBig.multiply(hslBig).divide(hslBig,BigDecimal.ROUND_DOWN).doubleValue();
            }
        }else if (AccountingUnitEnum.MINUTES.getKey().equals(hsdw)){
            double durationMinute = 0;
            if (unit.equals(AccountingUnitEnum.MINUTES)){
                durationMinute = duration;
            }else if (unit.equals(AccountingUnitEnum.HOUR)){
                durationMinute = duration*60;
            }else if (unit.equals(AccountingUnitEnum.DAY)){
                durationMinute = duration*24*60;
            }
            durationBig = new BigDecimal(durationMinute);
            if ((durationMinute/hsl) > Math.floor(durationMinute/hsl)){
                durationBig = new BigDecimal(Math.floor(durationMinute/hsl));
                itemDuration=durationBig.multiply(hslBig).add(hslBig,new MathContext(BigDecimal.ROUND_HALF_UP)).doubleValue();
            }else {
                itemDuration = durationBig.multiply(hslBig).divide(hslBig,BigDecimal.ROUND_DOWN).doubleValue();
            }
        }
        return itemDuration;
    }



    /**
     * 根据核算量、核算单位，计算出具体项目时长，向下核算
     * @param hsl 核算量
     * @param hsdw 核算单位
     * @param duration 时间值
     * @param unit 时间值单位
     * @return
     */
    public static double getItemdurationDown(double hsl, String hsdw,int duration, AccountingUnitEnum unit){
        double itemDuration = 0.0;
        BigDecimal durationBig = new BigDecimal(duration);
        BigDecimal hslBig = new BigDecimal(hsl);
        if (AccountingUnitEnum.DAY.getKey().equals(hsdw) || AccountingUnitEnum.ONCE.getKey().equals(hsdw)){
            itemDuration = hsl;
        }else if (AccountingUnitEnum.HOUR.getKey().equals(hsdw)){
            if (unit.equals(AccountingUnitEnum.MINUTES)){
                double durationHour = duration/60.0;
//                if (duration%60 > 0){
//                    durationHour = durationHour +1;
//                }
                durationBig = new BigDecimal(durationHour);
                if ((durationHour/hsl) > Math.floor(durationHour/hsl)){
                    // (durationHour/hsl)*hsl+hsl
                    durationBig = new BigDecimal(Math.floor(durationHour/hsl));
                    itemDuration = durationBig.multiply(hslBig).doubleValue();
                }else {
                    itemDuration = durationBig.multiply(hslBig).divide(hslBig,BigDecimal.ROUND_DOWN).doubleValue();
                }

            }else if (unit.equals(AccountingUnitEnum.HOUR)){
                if ((duration/hsl) > Math.floor(duration/hsl)){
                    durationBig = new BigDecimal(Math.floor(duration/hsl));
                    itemDuration=durationBig.multiply(hslBig).doubleValue();
                }else {
                    itemDuration = durationBig.multiply(hslBig).divide(hslBig,BigDecimal.ROUND_DOWN).doubleValue();
                }

            }

        }else if (AccountingUnitEnum.MINUTES.getKey().equals(hsdw)){
            if (unit.equals(AccountingUnitEnum.MINUTES)){
                if ((duration/hsl) > Math.floor(duration/hsl)){
                    durationBig = new BigDecimal(Math.floor(duration/hsl));
                    itemDuration=durationBig.multiply(hslBig).doubleValue();
                }else {
                    itemDuration = durationBig.multiply(hslBig).divide(hslBig,BigDecimal.ROUND_DOWN).doubleValue();
                }

            }else if (unit.equals(AccountingUnitEnum.HOUR)){
                int durationMinute = duration*60;
                durationBig = new BigDecimal(durationMinute);
                if ((durationMinute/hsl) > Math.floor(durationMinute/hsl)){
                    durationBig = new BigDecimal(Math.floor(durationMinute/hsl));
                    itemDuration=durationBig.multiply(hslBig).doubleValue();
                }else {
                    itemDuration = durationBig.multiply(hslBig).divide(hslBig,BigDecimal.ROUND_DOWN).doubleValue();
                }
            }
        }
        return itemDuration;
    }

    /**
     * 请假、外出时间扣出休息时间
     * @param kssj 开始时间
     * @param jssj 结束时间
     * @param scheduleResult 班次
     * @return
     */
    public static int removeRestTime(String kssj,String jssj,List<Map<String, Object>> scheduleResult,String analysisDate){
        scheduleResult = scheduleResult.stream().filter(e -> ClassSegmentTypeEnum.REST_AND_DINE.getKey().equals(e.get("bdlx")) ||
                ClassSegmentTypeEnum.REST_PERIOD.getKey().equals(e.get("bdlx")) || ClassSegmentTypeEnum.DINING_PERIOD.getKey().equals(e.get("bdlx"))).collect(Collectors.toList());
        int betweenMinutes = DateUtil.getBetWeenMinutes(kssj,jssj)-removeTime(kssj,jssj,scheduleResult,analysisDate);
        if (betweenMinutes < 0){
            betweenMinutes = 0;
        }
        return betweenMinutes;
    }

    /**
     * 开始时间和结束时间在所给班次中的占比时间
     * @param kssj
     * @param jssj
     * @param scheduleResult
     * @param analysisDate
     * @return
     */
    public static int removeTime(String kssj,String jssj,List<Map<String, Object>> scheduleResult,String analysisDate){
        int betweenMinutes = 0;
        log.debug("removeTime  scheduleResult : {}",scheduleResult);
        for (Map<String, Object> restSchedule :scheduleResult){
            String dtkssj = Utils.getkssjTime(restSchedule,analysisDate);
            String dtjssj = Utils.getjssjTime(restSchedule,analysisDate);

            if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dtkssj)) <=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dtjssj)) >=0){

                betweenMinutes += DateUtil.getBetWeenMinutes(dtkssj,dtjssj);

            }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dtkssj)) <=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dtjssj)) <=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dtkssj)) >=0){
                //休息时间在请假时间 右边
                betweenMinutes += DateUtil.getBetWeenMinutes(dtkssj,jssj);

            }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dtkssj)) >=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dtjssj)) >=0 && DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dtjssj)) <=0){
                //休息时间在请假时间 左边
                betweenMinutes += DateUtil.getBetWeenMinutes(kssj,dtjssj);

            }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dtkssj)) >=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dtjssj)) <=0){
                //请假时间在休息时间中间
                betweenMinutes += DateUtil.getBetWeenMinutes(kssj,jssj);;

            }
        }
        return betweenMinutes;
    }

    /**
     * 开始时间和结束时间在所给加班计划中的占比时间
     * @param kssj
     * @param jssj
     * @param overtimePlanList
     * @return
     */
    public static int removeTimeWithOvertimePlan(String kssj,String jssj,List<Map<String, Object>> overtimePlanList, Map<String, String> dateToBcxxMap){
        //获取作用时段包含计划加班的加班类型、并且勾选了“是否扣除时间区间内的就餐时长”的考勤项目集合
        String sql = "select id, mc, zysd, zdkcjcxxsc from uf_jcl_kq_kqxm where xmlx = ?";
        List<Map<String, Object>> jblxAttendanceList = DbTools.getSqlToList(sql, AttendanceItemTypeEnum.WORK_OVERTIME.getKey());
        List<String> needDealJblxIdList = jblxAttendanceList.stream()
                .filter(f -> Util.null2String(f.get("zysd")).contains(WorkForTimeEnum.PLAN_WORK_OVERTIME.getKey())
                        && "1".equals(Util.null2String(f.get("zdkcjcxxsc"))))
                .map(e->e.get("id").toString())
                .collect(Collectors.toList());

        //对加班计划数据逐条判断是否已经去除休息、就餐时长
        List<Map<String, Object>> newOvertimePlanList = new ArrayList<>();
        if (dateToBcxxMap != null && dateToBcxxMap.size() > 0) {
            for (Map<String, Object> overtimePlanItem : overtimePlanList) {
                if (needDealJblxIdList.contains(Util.null2String(overtimePlanItem.get("jblx")))) {
                    List<Map<String, Object>> overtimePlanWithNoRest = removeRestRange(overtimePlanItem, dateToBcxxMap);
                    if (overtimePlanWithNoRest.size() > 0) {
                        newOvertimePlanList.addAll(overtimePlanWithNoRest);
                    }
                } else {
                    newOvertimePlanList.add(overtimePlanItem);
                }
            }
        } else {
            newOvertimePlanList = overtimePlanList;
        }
        //遍历新的加班计划数据
        int betweenMinutes = 0;
        for (Map<String, Object> overtimePlanItem : newOvertimePlanList) {
            String dtkssj = overtimePlanItem.get("ksrq") + " " + overtimePlanItem.get("kssj");
            String dtjssj = overtimePlanItem.get("jsrq") + " " + overtimePlanItem.get("jssj");

            if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dtkssj)) <=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dtjssj)) >=0){

                betweenMinutes += DateUtil.getBetWeenMinutes(dtkssj,dtjssj);

            }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dtkssj)) <=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dtjssj)) <=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dtkssj)) >=0){
                //休息时间在请假时间 右边
                betweenMinutes += DateUtil.getBetWeenMinutes(dtkssj,jssj);

            }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dtkssj)) >=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dtjssj)) >=0 && DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dtjssj)) <=0){
                //休息时间在请假时间 左边
                betweenMinutes += DateUtil.getBetWeenMinutes(kssj,dtjssj);

            }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dtkssj)) >=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dtjssj)) <=0){
                //请假时间在休息时间中间
                betweenMinutes += DateUtil.getBetWeenMinutes(kssj,jssj);;

            }
        }
        return betweenMinutes;
    }

    /**
     * 去除加班计划中的休息/就餐时段，即将加班计划时段拆分为不含休息/就餐时段的多组加班计划数据
     * @param overtimePlanItem 加班计划信息
     * @param dateToBcxxMap 日期-班次信息映射
     * @return
     */
    private static List<Map<String, Object>> removeRestRange(Map<String, Object> overtimePlanItem, Map<String, String> dateToBcxxMap) {
        List<Map<String, Object>> result = new ArrayList<>();

        String startDate = Util.null2String(overtimePlanItem.get("ksrq"));
        String startTimePoint = Util.null2String(overtimePlanItem.get("kssj"));
        String endDate = Util.null2String(overtimePlanItem.get("jsrq"));
        String endTimePoint = Util.null2String(overtimePlanItem.get("jssj"));

        try {
            //获取需要比较的班次中的休息/就餐时段
            List<Map<String, String>> restRangeInfo = new ArrayList<>();
            List<String> dateList = DateUtil.getDatesBetween(DateUtil.beforeDay(startDate, 1), DateUtil.AfterDay(endDate, 1));
            for (String date : dateList) {
                String bcId = dateToBcxxMap.getOrDefault(date, "");
                bcId = "".equals(bcId) ? "" : bcId.split("-")[0];
                List<Map<String, String>> bcRestRangeInfoItem = getBcRestRangeInfo(bcId, date);
                if (bcRestRangeInfoItem.size() > 0) {
                    restRangeInfo.addAll(bcRestRangeInfoItem);
                }
            }
            if (restRangeInfo.size() > 0) {
                String overtimeStart = startDate + " " + startTimePoint;
                String overtimeEnd = endDate + " " + endTimePoint;
                restRangeInfo.sort(Comparator.comparing(o->o.get("startTime")));
                String restRangeStart;
                String restRangeEnd;
                List<Map<String, String>> splitRangeInfo = new ArrayList<>();
                Map<String, String> splitRangeItem;
                for (Map<String, String> restRange : restRangeInfo) {
                    restRangeStart = Util.null2String(restRange.get("startTime"));
                    restRangeEnd = Util.null2String(restRange.get("endTime"));
                    if ("".equals(restRangeStart) || "".equals(restRangeEnd)) {
                        continue;
                    }
                    //分情况处理休息/就餐时段和加班区间的交集情况
                    if (restRangeStart.compareTo(overtimeStart) <= 0 && restRangeEnd.compareTo(overtimeEnd) >= 0) {
                        //1-加班区间完全处于休息时段内
                        overtimeStart = overtimeEnd;
                        break;
                    } else if (overtimeStart.compareTo(restRangeStart) < 0 && overtimeEnd.compareTo(restRangeEnd) > 0) {
                        //2-休息时段完全处于加班区间内
                        splitRangeItem = new HashMap<>();
                        splitRangeItem.put("startTime", overtimeStart);
                        splitRangeItem.put("endTime", restRangeStart);
                        splitRangeInfo.add(splitRangeItem);
                        //更新加班开始时间
                        overtimeStart = restRangeEnd;
                    } else if (restRangeStart.compareTo(overtimeStart) < 0 && restRangeEnd.compareTo(overtimeStart) > 0 && restRangeEnd.compareTo(overtimeEnd) < 0) {
                        //3仅仅休息时段尾部部分处于加班区间内
                        //更新加班开始时间
                        overtimeStart = restRangeEnd;
                    } else if (restRangeStart.compareTo(overtimeStart) > 0 && restRangeStart.compareTo(overtimeEnd) < 0 && restRangeEnd.compareTo(overtimeEnd) > 0) {
                        //4仅仅休息时段首部部分处于加班区间内
                        splitRangeItem = new HashMap<>();
                        splitRangeItem.put("startTime", overtimeStart);
                        splitRangeItem.put("endTime", restRangeStart);
                        splitRangeInfo.add(splitRangeItem);
                        break;
                    }
                }
                //判断加班区间除去被拆分的前部分，是否还有剩余尾部
                if (overtimeStart.compareTo(overtimeEnd) < 0) {
                    splitRangeItem = new HashMap<>();
                    splitRangeItem.put("startTime", overtimeStart);
                    splitRangeItem.put("endTime", overtimeEnd);
                    splitRangeInfo.add(splitRangeItem);
                }
                //对于被拆分的加班时间段，处理成新的多组加班计划明细
                Map<String, Object> newOvertimePlanItem;
                for (Map<String, String> item : splitRangeInfo) {
                    newOvertimePlanItem = new HashMap<>(overtimePlanItem);
                    newOvertimePlanItem.put("ksrq", item.get("startTime").split(" ")[0]);
                    newOvertimePlanItem.put("kssj", item.get("startTime").split(" ")[1]);
                    newOvertimePlanItem.put("jsrq", item.get("endTime").split(" ")[0]);
                    newOvertimePlanItem.put("jssj", item.get("endTime").split(" ")[1]);
                    result.add(newOvertimePlanItem);
                }
            } else {
                result.add(overtimePlanItem);
            }
        } catch (Exception e) {
            log.error("removeRestRange error:{}",e.getMessage());
        }
        return result;
    }

    /**
     * 获取对应日期班次中的休息/就餐时段信息
     * @param bcId 班次id
     * @param date 日期
     * @return
     */
    private static List<Map<String, String>> getBcRestRangeInfo(String bcId, String date) {
        List<String> countBdlxList = new ArrayList<>();
        countBdlxList.add(ClassSegmentTypeEnum.REST_AND_DINE.getKey());
        countBdlxList.add(ClassSegmentTypeEnum.REST_PERIOD.getKey());
        countBdlxList.add(ClassSegmentTypeEnum.DINING_PERIOD.getKey());
        String sql = "select id, bdlx, gsrq, kssj as dtkssj, jssj as dtjssj from uf_jcl_kq_bcxx_dt1 where mainid  = " + bcId;
        List<Map<String, Object>> bcDetailData = DbTools.getSqlToList(sql);
        bcDetailData = bcDetailData.stream().filter(e -> countBdlxList.contains(Util.null2String(e.get("bdlx")))).collect(Collectors.toList());

        List<Map<String, String>> result = new ArrayList<>();
        Map<String, String> itemMap;
        for (Map<String, Object> bcDetailItem : bcDetailData){
            String dtkssj = Utils.getkssjTime(bcDetailItem, date);
            String dtjssj = Utils.getjssjTime(bcDetailItem, date);
            itemMap = new HashMap<>();
            itemMap.put("startTime", dtkssj);
            itemMap.put("endTime", dtjssj);
            result.add(itemMap);
        }
        return result;
    }

    /**
     * 开始时间和结束时间在班段类型中所占的时间
     * @param kssj
     * @param jssj
     * @param scheduleResult
     * @param analysisDate
     * @return
     */
    public static Map<String,Object> getAskLeaveAndEvctionProportion(String kssj,String jssj,List<Map<String, Object>> scheduleResult,String analysisDate){
        Map<String,Object> resultMap = Maps.newHashMap();
        for (Map<String, Object> restSchedule :scheduleResult){
            String dtkssj = Utils.getkssjTime(restSchedule,analysisDate);
            String dtjssj = Utils.getjssjTime(restSchedule,analysisDate);

            int betweenMinutes = 0;
            if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dtkssj)) <=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dtjssj)) >=0){
                //休息时间在请假时间中间
                betweenMinutes = DateUtil.getBetWeenMinutes(dtkssj,dtjssj);
                log.debug("休息时间在请假时间中间");
            }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dtkssj)) <=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dtjssj)) <=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dtkssj)) >=0){
                //休息时间在请假时间 右边
                betweenMinutes = DateUtil.getBetWeenMinutes(dtkssj,jssj);
                log.debug("休息时间在请假时间 右边");
            }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dtkssj)) >=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dtjssj)) >=0 && DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dtjssj)) <=0){
                //休息时间在请假时间 左边
                betweenMinutes = DateUtil.getBetWeenMinutes(kssj,dtjssj);
                log.debug("休息时间在请假时间 左边");
            }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(dtkssj)) >=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(dtjssj)) <=0){
                //请假时间在休息时间中间
                betweenMinutes = 0;
                log.debug("请假时间在休息时间中间");
            }
            if (betweenMinutes > 0){
                if (resultMap.get(restSchedule.get("bdlx")) == null){
                    resultMap.put(restSchedule.get("bdlx").toString(),betweenMinutes);
                }else {
                    betweenMinutes = betweenMinutes +  Integer.valueOf(resultMap.get(restSchedule.get("bdlx")).toString());
                    resultMap.put(restSchedule.get("bdlx").toString(),betweenMinutes);
                }

            }
        }

        return resultMap;
    }

    /**
     * 统计各种类型班段所占时间,除请假和出差外
     * @return
     */
    public static Map<String,Object> getClassSegmentTimeProportion(List<Map<String,Object>> scheduleResult,String analysisDate){
        Map<String,Object> resultMap = Maps.newHashMap();
        for (Map<String,Object> schedule: scheduleResult){
            String bdlx = Util.null2String(schedule.get("bdlx"));
            int edfzs = Util.null2String(schedule.get("edfzs")).equals("")?0:Integer.valueOf(Util.null2String(schedule.get("edfzs")));
            if (!bdlx.equals(ClassSegmentTypeEnum.ASK_FOR_LEAVE.getKey()) && !bdlx.equals(ClassSegmentTypeEnum.EVECTION.getKey())){
                if (bdlx.equals(ClassSegmentTypeEnum.OVERTIME_PLAN.getKey())){
                    String kssj = getkssjTime(schedule,analysisDate);
                    String jssj = getjssjTime(schedule,analysisDate);
                    edfzs = DateUtil.getBetWeenMinutes(kssj,jssj);
                }
                if (resultMap.get(bdlx) != null){
                    edfzs = edfzs +  Integer.valueOf(resultMap.get(bdlx).toString());
                }

                resultMap.put(bdlx,edfzs);
            }
        }
        return resultMap;

    }

    /**
     * 扣除就餐时间
     * @param kssj 开始时间
     * @param jssj 结束时间
     * @param scheduleResult 班次
     * @return
     */
    public static int dinnerTime(String kssj,String jssj,List<Map<String, Object>> scheduleResult,String analysisDate){
        scheduleResult = scheduleResult.stream().filter(e ->Utils.ifRestClassSegment(e.get("bdlx").toString())).collect(Collectors.toList());
        int dinnerTime = removeTime(kssj,jssj,scheduleResult,analysisDate);
        return dinnerTime;
    }

    /**
     * 请假外出在加班中所占时间
     * @return
     */
    public static int getStartAndEndTime(String kssj,String jssj,Map<String, Object> leaveMap){
        String leavekssj = leaveMap.get("ksrq") + " "+leaveMap.get("kssj");
        String leavejssj = leaveMap.get("jsrq")+ " "+leaveMap.get("jssj");
        int betweenMinutes=0;
        if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(leavekssj)) <=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(leavejssj)) >=0){
            //请假外出时间在中间
            betweenMinutes =  DateUtil.getBetWeenMinutes(leavekssj,leavejssj);
            log.debug("请假外出时间在中间");
        }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(leavekssj)) <=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(leavejssj)) <=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(leavekssj)) >=0){
            //请假外出时间 右边
            betweenMinutes =  DateUtil.getBetWeenMinutes(leavekssj,jssj);
            log.debug("请假外出时间 右边");
        }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(leavekssj)) >=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(leavejssj)) >=0 && DateUtil.getTime(kssj).compareTo(DateUtil.getTime(leavejssj)) <=0){
            //休请假外出时间 左边
            betweenMinutes = DateUtil.getBetWeenMinutes(kssj,leavejssj);
            log.debug("请假外出时间 左边");
        }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(leavekssj)) >=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(leavejssj)) <=0){
            //请假外出时间中间
            betweenMinutes = DateUtil.getBetWeenMinutes(kssj,jssj);
            log.debug("加班实际在请假外出时间中间");
        }
        return betweenMinutes;
    }

    /**
     * map中的开始时间和结束时间，在kssj和jssj中占据的分钟数
     * @return
     */
    public static int getIntersectionTime(String kssj,String jssj,Map<String, Object> map,List<Map<String, Object>> scheduleResult,String analysisDate){
        String leavekssj = map.get("kssj").toString();
        String leavejssj = map.get("jssj").toString();
        int betweenMinutes=0;
        if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(leavekssj)) <=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(leavejssj)) >=0){
            //时间在中间
            betweenMinutes =  removeRestTime(leavekssj,leavejssj,scheduleResult,analysisDate);
            log.debug("时间在中间,被包含");
        }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(leavekssj)) <=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(leavejssj)) <=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(leavekssj)) >=0){
            //时间 右边
            betweenMinutes =  removeRestTime(leavekssj,jssj,scheduleResult,analysisDate);
            log.debug("时间 右边");
        }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(leavekssj)) >=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(leavejssj)) >=0 && DateUtil.getTime(kssj).compareTo(DateUtil.getTime(leavejssj)) <=0){
            //时间 左边
            betweenMinutes = removeRestTime(kssj,leavejssj,scheduleResult,analysisDate);
            log.debug("时间 左边");
        }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(leavekssj)) >=0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(leavejssj)) <=0){
            //请假外出时间中间
            betweenMinutes = removeRestTime(kssj,jssj,scheduleResult,analysisDate);
            log.debug("时间在中间,包含");
        }
        return betweenMinutes;
    }

    /**
     * 获得建模表对应的模块ID
     * @return
     */
    public static Map<String,String> getFormmodeIdMap(){
        String sql = "select c.id,b.tablename  from uf_jcl_form_table a left join workflow_bill b on a.tablename=b.tablename left join modeinfo c on b.id=c.formid where  (c.isDelete is null or  c.isDelete <> '1')";
        List<Map<String,Object>> dataList = DbTools.getSqlToList(sql);
        return dataList.stream().collect(Collectors.toMap(e->e.get("tablename").toString(),e->e.get("id").toString()));

    }

    /**
     * 插入
     * @param tableName
     * @param dataMap
     * @param formmodeIdMap
     */
    public static boolean InsertFormTable(String tableName,Map<String,Object> dataMap,Map<String,String> formmodeIdMap){
        String formmodeId = formmodeIdMap.get(tableName);
        if (!tableName.contains("_dt")){
            dataMap.put("formmodeid",formmodeId);
            dataMap.put("modeuuid", UUID.randomUUID().toString());
            dataMap.put("modedatacreater","1");
            dataMap.put("modedatacreatertype","0");
            dataMap.put("modedatacreatedate",DateUtil.getCurrentTime().split(" ")[0]);
            dataMap.put("modedatacreatetime",DateUtil.getCurrentTime().split(" ")[1]);
        }
        return CommonUtil.makeInsertSql(tableName,dataMap);
    }

    /**
     * 根据班段类型获得作用时段
     * @param bdlx
     * @return
     */
    public static String getWorkFor(String bdlx){
        String workFor="";
        if (ClassSegmentTypeEnum.WORK_TIME.getKey().equals(bdlx)){
            workFor = WorkForTimeEnum.WORK_TIME.getKey();
        }else if (ClassSegmentTypeEnum.EXTENDED_OVERTIME.getKey().equals(bdlx)){
            workFor = WorkForTimeEnum.DELAY_TO_WORK_OVERTIME.getKey();
        }else if (ClassSegmentTypeEnum.EARLY_OVERTIME.getKey().equals(bdlx)){
            workFor = WorkForTimeEnum.EARLY_TO_WORK_OVERTIME.getKey();
        }else if (ClassSegmentTypeEnum.OVERTIME_PLAN.getKey().equals(bdlx)){
            workFor = WorkForTimeEnum.PLAN_WORK_OVERTIME.getKey();
        }else if (ClassSegmentTypeEnum.ASK_FOR_LEAVE.getKey().equals(bdlx)){
            workFor = WorkForTimeEnum.LEAVE_TIME.getKey();
        }else if (ClassSegmentTypeEnum.EVECTION.getKey().equals(bdlx)){
            workFor = WorkForTimeEnum.EVECTION.getKey();
        }else if (ClassSegmentTypeEnum.OVERTIME_IN_CLASS.getKey().equals(bdlx)){
            workFor = WorkForTimeEnum.OVERTIME_IN_CLASS.getKey();
        }
        return workFor;
    }

    /**
     * 根据作用时段获得班段类型
     * @param workFor
     * @return
     */
    public static String getClassSegmenByWorkFor(String workFor){
        String bdlx="";
        if (WorkForTimeEnum.WORK_TIME.getKey().equals(workFor)){
            bdlx = ClassSegmentTypeEnum.WORK_TIME.getKey();
        }else if (WorkForTimeEnum.DELAY_TO_WORK_OVERTIME.getKey().equals(workFor)){
            bdlx = ClassSegmentTypeEnum.EXTENDED_OVERTIME.getKey();
        }else if (WorkForTimeEnum.EARLY_TO_WORK_OVERTIME.getKey().equals(workFor)){
            bdlx = ClassSegmentTypeEnum.EARLY_OVERTIME.getKey();
        }else if (WorkForTimeEnum.PLAN_WORK_OVERTIME.getKey().equals(workFor)){
            bdlx = ClassSegmentTypeEnum.OVERTIME_PLAN.getKey();
        }else if (WorkForTimeEnum.LEAVE_TIME.getKey().equals(workFor)){
            bdlx = ClassSegmentTypeEnum.ASK_FOR_LEAVE.getKey();
        }else if (WorkForTimeEnum.EVECTION.getKey().equals(workFor)){
            bdlx = ClassSegmentTypeEnum.EVECTION.getKey();
        }else if (WorkForTimeEnum.OVERTIME_IN_CLASS.getKey().equals(workFor)){
            bdlx = ClassSegmentTypeEnum.OVERTIME_IN_CLASS.getKey();
        }
        return bdlx;
    }

    /**
     * 获得半天时间
     * @param scheduleResult
     * @return
     */
    public double getHalfDay(List<Map<String, Object>> scheduleResult){
        scheduleResult = scheduleResult.stream().filter(e -> !ClassSegmentTypeEnum.OVERTIME_PLAN.getKey().equals(e.get("bdlx")) &&
                !ClassSegmentTypeEnum.ASK_FOR_LEAVE.getKey().equals(e.get("bdlx")) && !ClassSegmentTypeEnum.EVECTION.getKey().equals(e.get("bdlx"))).collect(Collectors.toList());
        if (scheduleResult.size() > 0){
            String btgz = Util.null2String(scheduleResult.get(0).get("btgz"));
            String fgsjd = Util.null2String(scheduleResult.get(0).get("fgsjd"));
            if (HalfDayRuleREnum.BY_CLASS_SET.getKey().equals(btgz)){

            }else if (HalfDayRuleREnum.FIXED_DURATION.getKey().equals(btgz)){

            }else if (HalfDayRuleREnum.HALF_TOTAL_DURATION.getKey().equals(btgz)){

            }else if (HalfDayRuleREnum.HALF_RATED_DURATION.getKey().equals(btgz)){

            }
        }
        return 0;
    }

    /**
     * 重新获得排班
     * @param dataList
     * @return
     */
    public static List<Map<String, Object>> getSchedulingList(List<Map<String, Object>> dataList){
        Map<String,List<Map<String, Object>>> dataMaps = dataList.stream().collect(Collectors.groupingBy(e->Util.null2String(e.get("bcrq"))));
        List<Map<String, Object>> resultList = Lists.newArrayList();
        for (Map.Entry<String,List<Map<String, Object>>> entry:dataMaps.entrySet()){
            String bcrq = entry.getKey();
            List<Map<String, Object>> classList = entry.getValue();
            if (classList.size() > 1){
                classList = classList.stream().filter(e->!e.get("pbtj").equals(RegularScheduleTypeEnum.REGULAR.getKey())).collect(Collectors.toList());
                classList = classList.stream().sorted(Comparator.comparing(e->DateUtil.getTime(e.get("modedatacreatedate")+" "+e.get("modedatacreatetime")).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());
                if (classList.size() > 0){
                    resultList.add(classList.get(classList.size()-1));
                }else {
                    resultList.add(entry.getValue().get(0));
                }
            }else {
                resultList.addAll(classList);
            }
        }

        return resultList;
    }

    /**
     * 相减
     * @param value1
     * @param value2
     * @return
     */
    public static double subtract(double value1,double value2){

        return new BigDecimal(String.valueOf(value1)).subtract(new BigDecimal(String.valueOf(value2)),new MathContext(BigDecimal.ROUND_HALF_UP)).doubleValue();
    }

    /**
     * 相加
     * @param value1
     * @param value2
     * @return
     */
    public static double add(double value1,double value2){

        return new BigDecimal(String.valueOf(value1)).add(new BigDecimal(String.valueOf(value2)),new MathContext(BigDecimal.ROUND_HALF_UP)).doubleValue();
    }

    /**
     *  相乘
     * @param value1
     * @param value2
     * @return
     */
    public static double multiply(double value1,double value2){

        return new BigDecimal(String.valueOf(value1)).multiply(new BigDecimal(String.valueOf(value2)),new MathContext(BigDecimal.ROUND_HALF_UP)).doubleValue();
    }

    /**
     *  相除
     * @param value1
     * @param value2
     * @return
     */
    public static double divide(double value1, double value2){

        return new BigDecimal(String.valueOf(value1)).divide(new BigDecimal(String.valueOf(value2)), 2, RoundingMode.HALF_UP).doubleValue();
    }

    /**
     * 根据日期和时间组装日期时间
     * @param date
     * @param time
     * @return
     */
    public static String installTime(String date ,String time){
        return date+" "+time;
    }

    /**
     * 开始时间大于结束时间
     * @param beginTime
     * @param endTime
     * @return
     */
    public static boolean dateGreaterThan(String beginTime,String endTime){
        return DateUtil.getTime(beginTime).compareTo(DateUtil.getTime(endTime)) >0;
    }

    /**
     * 根据日期，日历名称id，获得当前日期类型
     * @param date
     * @param rlmc
     * @return
     */
    public static String getDateType(String date,String rlmc){
        String sql = "select rqlx from uf_jcl_kq_rlxx where rlmc=? and rq=?";
        Map<String,Object> data = DbTools.getSqlToMap(sql,rlmc,date.split(" ")[0]);
        return Util.null2String(data.get("rqlx"));
    }
    /**
     * 根据日期，分部，获得该分部下的默认日历的当前日期类型
     * @param subcompanyid1
     * @param date
     * @return
     */
    public static String getDefaultDateType(String subcompanyid1,String date){
        String rqlx = "";
        String parentSubcompanyids = "";
        try {

            parentSubcompanyids = new SubCompanyComInfo().getAllParentSubcompanyId(subcompanyid1,parentSubcompanyids);
        }catch (Exception e){
            log.error("getDefaultDateType error:[{}]",e);
        }
        parentSubcompanyids = subcompanyid1+parentSubcompanyids;
        String sql = "select b.szjg,a.rqlx from uf_jcl_kq_rlxx a left join uf_jcl_kq_rlmc b on a.rlmc=b.id where b.mrrl=1 and b.szjg in ("+parentSubcompanyids+") and a.rq=?";
        List<Map<String,Object>> dataList = DbTools.getSqlToList(sql,date);
        Map<String,Object> dataMap = dataList.stream().collect(Collectors.toMap(e->e.get("szjg").toString(),e->e.get("rqlx")));
        for (int i=0;i<parentSubcompanyids.split(",").length;i++){
            String subId = parentSubcompanyids.split(",")[i];
            rqlx = Util.null2String(dataMap.get(subId));
            if (!"".equals(rqlx)){
                break;
            }
        }
        return rqlx;
    }

    /**
     * 获得默认周期
     * @param subcompanyid1
     * @return
     */
    public static String getDefaultAttendanceCycle(String subcompanyid1){
        String defaultCycle = "";
        String parentSubcompanyids = "";
        try {

            parentSubcompanyids = new SubCompanyComInfo().getAllParentSubcompanyId(subcompanyid1,parentSubcompanyids);
        }catch (Exception e){
            log.error("getDefaultDateType error:[{}]",e);
        }
        parentSubcompanyids = subcompanyid1+parentSubcompanyids;
        String sql = "select id,szjg from uf_jcl_kq_kqzqmc where szjg in ("+parentSubcompanyids+") and mrzq=1";
        List<Map<String,Object>> dataList = DbTools.getSqlToList(sql);
        Map<String,Object> dataMap = dataList.stream().collect(Collectors.toMap(e->e.get("szjg").toString(),e->e.get("id")));

        for (int i=0;i<parentSubcompanyids.split(",").length;i++){
            String subId = parentSubcompanyids.split(",")[i];
            defaultCycle = Util.null2String(dataMap.get(subId));
            if (!"".equals(defaultCycle)){
                break;
            }
        }
        return defaultCycle;
    }

    /**
     * 获得人员分部对应年度的默认日历
     * @param subcompanyid1
     * @param year
     * @return
     */
    public static List<Map<String,Object>> getDefaultDateList(String subcompanyid1,String year){
        List<Map<String,Object>> resultList=null;
        String parentSubcompanyids = "";
        try {
            parentSubcompanyids = new SubCompanyComInfo().getAllParentSubcompanyId(subcompanyid1,parentSubcompanyids);
        }catch (Exception e){
            log.error("getDefaultDateType error:[{}]",e);
        }
        parentSubcompanyids = subcompanyid1+parentSubcompanyids;
        String sql = "select a.nd,a.rq,a.nlrq,a.rqlx,a.xq,a.rlmc,b.szjg from uf_jcl_kq_rlxx a left join uf_jcl_kq_rlmc b on a.rlmc=b.id where b.mrrl=1 and b.szjg in ("+parentSubcompanyids+") and a.nd=?";
        List<Map<String,Object>> dataList = DbTools.getSqlToList(sql,year);
        Map<String,List<Map<String,Object>>> dataMap = dataList.stream().collect(Collectors.groupingBy(e->e.get("szjg").toString()));
        for (int i=0;i<parentSubcompanyids.split(",").length;i++){
            String subId = parentSubcompanyids.split(",")[i];
            resultList = dataMap.get(subId);
            if (resultList != null){
                break;
            }
        }
        return resultList;
    }

    /**
     * 根据核算单位、时间转换成分钟
     * @param time 时间
     * @param hsdw 核算单位
     * @return
     */
    public static double converTimeToMinute(double time,String hsdw){
        if (AccountingUnitEnum.DAY.getKey().equals(hsdw)){
            time = time*24*60;
        }else if (AccountingUnitEnum.HOUR.getKey().equals(hsdw)){
            time = time*60;
        }

        return time;
    }

    /**
     * 获得班次的开始时间的提前时间
     * @param schedulingMap
     * @param date
     * @return
     */
    public static String getkssjEarliestTime(Map<String,Object> schedulingMap,String date){
        String tqdkfzs = Util.null2String(schedulingMap.get("tqdkfzs"));
        if ("".equals(tqdkfzs)){
            tqdkfzs = "60";
        }
        return DateUtil.beforeMinutes(getkssjTime(schedulingMap,date),Integer.valueOf(tqdkfzs));
    }

    /**
     * 获得班次的开始时间
     * @param schedulingMap 班次信息
     * @param date 分析日期
     * @return
     */
    public static String getkssjTime(Map<String,Object> schedulingMap,String date){
        if (ifAskforOrEvctionClassSegment(schedulingMap.get("bdlx").toString())){
            return schedulingMap.get("dtkssj").toString();
        }
        String gsrq = Util.null2String(schedulingMap.get("gsrq"));
        String kssj = Util.null2String(schedulingMap.get("dtkssj"));
        if (gsrq.equals(ClassBelongToEnum.YESTERDAY.getKey())){
            date = DateUtil.beforeDay(date,1);
        }else if (gsrq.equals(ClassBelongToEnum.NEXTDAY.getKey())){
            date = DateUtil.AfterDay(date,1);
        }else if (gsrq.equals(ClassBelongToEnum.NOWDAY.getKey())){
            date = date;
        }
        kssj = date+" "+kssj;

        return kssj;
    }
    /**
     * 获得班次的结束时间的退后时间
     * @param schedulingMap
     * @param date
     * @return
     */
    public static String getjssjLastestTime(Map<String,Object> schedulingMap,String date){

        String thdkfzs = Util.null2String(schedulingMap.get("thdkfzs"));
        if ("".equals(thdkfzs)){
            thdkfzs = "60";
        }

        return DateUtil.AfterMinutes(getjssjTime(schedulingMap,date),Integer.valueOf(thdkfzs));
    }
    /**
     * 获得班次的结束时间
     * @param schedulingMap 班次信息
     * @param date 分析日期
     * @return
     */
    public static String getjssjTime(Map<String,Object> schedulingMap,String date){
        if (ifAskforOrEvctionClassSegment(schedulingMap.get("bdlx").toString())){
            return schedulingMap.get("dtjssj").toString();
        }
        String gsrq = Util.null2String(schedulingMap.get("gsrq"));
        String jssj = Util.null2String(schedulingMap.get("dtjssj"));
        String kssj = Util.null2String(schedulingMap.get("dtkssj"));
        if (gsrq.equals(ClassBelongToEnum.YESTERDAY.getKey())){
            date = DateUtil.beforeDay(date,1);
        }else if (gsrq.equals(ClassBelongToEnum.NEXTDAY.getKey())){
            date = DateUtil.AfterDay(date,1);
        }else if (gsrq.equals(ClassBelongToEnum.NOWDAY.getKey())){
            date = date;
        }
        jssj = date+" "+jssj;
        kssj = date+" "+kssj;
        if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(jssj)) >= 0) {
            jssj = DateUtil.AfterDay(date, 1) + " " + Util.null2String(schedulingMap.get("dtjssj"));
        }

        return jssj;
    }

    /**
     * 判断是否是加班类型时段
     * @param classSegmentType
     * @return
     */
    public static boolean ifOverTimeClassSegment(String classSegmentType){
        if (classSegmentType.equals(ClassSegmentTypeEnum.EXTENDED_OVERTIME.getKey()) || classSegmentType.equals(ClassSegmentTypeEnum.EARLY_OVERTIME.getKey())
                || classSegmentType.equals(ClassSegmentTypeEnum.OVERTIME_IN_CLASS.getKey()) || classSegmentType.equals(ClassSegmentTypeEnum.OVERTIME_PLAN.getKey())){
            return true;
        }else {
            return false;
        }
    }

    /**
     * 判断是否是休息类型时段
     * @param classSegmentType
     * @return
     */
    public static boolean ifRestClassSegment(String classSegmentType){
        if (classSegmentType.equals(ClassSegmentTypeEnum.REST_AND_DINE.getKey()) || classSegmentType.equals(ClassSegmentTypeEnum.REST_PERIOD.getKey())
                || classSegmentType.equals(ClassSegmentTypeEnum.DINING_PERIOD.getKey())){
            return true;
        }else {
            return false;
        }
    }
    /**
     * 判断是否是请假出差
     * @param classSegmentType
     * @return
     */
    public static boolean ifAskforOrEvctionClassSegment(String classSegmentType){
        if (classSegmentType.equals(ClassSegmentTypeEnum.ASK_FOR_LEAVE.getKey()) || classSegmentType.equals(ClassSegmentTypeEnum.EVECTION.getKey())){
            return true;
        }else {
            return false;
        }
    }

    /**
     * 转换成double
     * @param num
     * @return
     */
    public static double convertDouble(Object num){
        return Util.null2String(num).equals("")?0:Double.valueOf(Util.null2String(num));
    }
    public static ClockPointDTO getClockPointDTO(List<ClockPointDTO> clockPointDTOList,ClockPointEnum pointType,String time){


        return null;
    }

    /**
     * 将班次转换成卡点并按照打卡时间从小到大排列
     * @param scheduleResult
     * @return
     */
    public static List<ClockPointDTO> converToClockPointBySchedule(List<Map<String, Object>> scheduleResult,String analysisDate){
        List<ClockPointDTO> clockPointDTOList = Lists.newArrayList();
        for (Map<String, Object> schedule: scheduleResult){
            ClockPointDTO startClockPointDTO = ClockPointDTO.builder().classTime(Utils.getkssjTime(schedule,analysisDate)).pointType(ClockPointEnum.START).classSegmentType(schedule.get("bdlx").toString()).build();
            ClockPointDTO endClockPointDTO = ClockPointDTO.builder().classTime(Utils.getjssjTime(schedule,analysisDate)).pointType(ClockPointEnum.END).classSegmentType(schedule.get("bdlx").toString()).build();
            if (ifAskforOrEvctionClassSegment(schedule.get("bdlx").toString())){
                startClockPointDTO.setPointType(ClockPointEnum.END);
                endClockPointDTO.setPointType(ClockPointEnum.START);
            }
            clockPointDTOList.add(startClockPointDTO);
            clockPointDTOList.add(endClockPointDTO);
        }
        clockPointDTOList = clockPointDTOList.stream().sorted(Comparator.comparing(e->DateUtil.getTime(e.getClassTime()).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList());
        return clockPointDTOList;
    }

    /**
     * 获得班段包含的异常集合
     * @param scheduleMap 班段
     * @param abnormalScheduleList 异常集合
     * @return
     */
    public static List<Map<String,Object>> getAbnormalListBySchedule(Map<String, Object> scheduleMap,List<Map<String,Object>> abnormalScheduleList,String analysisDate){
        String kssj = getkssjTime(scheduleMap,analysisDate);
        String jssj = getjssjTime(scheduleMap,analysisDate);
        List<Map<String,Object>> resultList = abnormalScheduleList.stream().filter(e->{
            ClockPointEnum pointType = (ClockPointEnum)e.get("pointType");
            String time = "";
            if (pointType == ClockPointEnum.END){
                time = jssj;
            }else if (pointType == ClockPointEnum.START){
                time = kssj;
            }
            if (DateUtil.getTime(time).compareTo(DateUtil.getTime(e.get("pointTime").toString())) == 0){
                return true;
            }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(e.get("pointTime").toString())) <0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(e.get("pointTime").toString())) >0){
                return true;
            }else {
                return false;
            }

        }).collect(Collectors.toList());
        return resultList;
    }

    /**
     * 获得异常所处的班段集合
     * @param scheduleMapList 班段
     * @param abnormalList 异常集合
     * @return
     */
    public static Set<Map<String,Object>> getScheduleByAbnormalList(List<Map<String,Object>> scheduleMapList,List<Map<String,Object>> abnormalList,String analysisDate){
        Set<Map<String,Object>> resultList = Sets.newHashSet();
        for (Map<String,Object> abnormal:abnormalList){
            ClockPointEnum pointType = (ClockPointEnum)abnormal.get("pointType");
            String pointTime = abnormal.get("pointTime").toString();
            for (Map<String,Object> scheduleMap:scheduleMapList){
                String kssj = getkssjTime(scheduleMap,analysisDate);
                String jssj = getjssjTime(scheduleMap,analysisDate);
                String time = "";
                if (pointType == ClockPointEnum.END){
                    time = jssj;
                }else if (pointType == ClockPointEnum.START){
                    time = kssj;
                }
                if (DateUtil.getTime(time).compareTo(DateUtil.getTime(pointTime)) == 0){
                    resultList.add(scheduleMap);
                }else if (DateUtil.getTime(kssj).compareTo(DateUtil.getTime(pointTime)) <0 && DateUtil.getTime(jssj).compareTo(DateUtil.getTime(pointTime)) >0){
                    resultList.add(scheduleMap);
                }
            }
        }
        return resultList;
    }

    /**
     * 合并一个班段上的异常
     * @param scheduleMapList
     * @param abnormalScheduleList
     * @param analysisDate
     * @return
     */
    public static List<Map<String,Object>> mergeOneScheduleAbnormal(List<Map<String,Object>> scheduleMapList,List<Map<String,Object>> abnormalScheduleList,String analysisDate){
        List<Map<String,Object>> resultList = Lists.newArrayList();
        for (Map<String,Object> scheduleMap:scheduleMapList){
            List<Map<String,Object>> abnormals = getAbnormalListBySchedule(scheduleMap,abnormalScheduleList,analysisDate);
            if (abnormals.size() == 1){
                resultList.add(abnormals.get(0));
            }else if (abnormals.size() > 1){
                String kssj = getkssjTime(scheduleMap,analysisDate);
                String jssj = getjssjTime(scheduleMap,analysisDate);
                int betweenMinute = DateUtil.getBetWeenMinutes(kssj,jssj);
                List<Map<String,Object>> filterAbnormals = abnormals.stream().filter(e->e.get("itemType") == AttendanceItemTypeEnum.MISSE_CARD ||
                        Integer.valueOf(e.get("betweenMinutes") == null?"0":e.get("betweenMinutes").toString()) >= betweenMinute).collect(Collectors.toList());
                if (filterAbnormals.size() > 0){
                    resultList.add(filterAbnormals.get(0));
                }else {
                    resultList.addAll(abnormals);
                }
            }
        }

        return resultList;
    }

    /**
     * 转换sql语句
     * @param sqltj
     * @return
     */
    public static String converSQL(String sqltj){
        sqltj = sqltj.replace("ｓｅｌｅｃｔ","select");
        sqltj = sqltj.replace("ＳＥＬＥＣＴ","select");
        sqltj = sqltj.replace("Ｓｅｌｅｃｔ","select");
        sqltj = sqltj.replace("ａｎｄ","and");
        sqltj = sqltj.replace("ＡＮＤ","and");
        sqltj = sqltj.replace("ｏｒ","or");
        sqltj = sqltj.replace("ＯＲ","or");
        sqltj = sqltj.replace("ｊｏｉｎ","join");
        sqltj = sqltj.replace("ＪＯＩＮ","join");
        sqltj = sqltj.replace("ｌｉｋｅ","like");
        sqltj = sqltj.replace("ＬＩＫＥ","like");
        sqltj = sqltj.replace("ｉｎ","in");
        sqltj = sqltj.replace("ＩＮ","in");
        sqltj = sqltj.replace("ｕｎｉｏｎ","union");
        return sqltj;
    }

}
